⚡ 30 秒速记
- 拆包目标是减少关键路径下载与执行
- 动态
import()给按需加载边界 splitChunks处理共享依赖和分组策略- 拆得太碎会增加请求与加载瀑布
- 发布保留旧资源,处理懒加载失败与重试
代码拆分是把暂时用不到的代码推迟加载,让用户更快用上当前页面。 路由、大编辑器或图表通常适合动态导入,共享依赖再根据复用情况整理。拆分后既要看首屏资源少了多少,也要看进入下一页是否出现连续等待。发布时还要考虑旧页面继续请求旧代码块的情况,否则首页正常,用户点到某个功能才会遇到加载失败。
版本校准: 旧文中的 webpack 4、JSONP 更新清单或 react-hot-loader 代码用于解释历史链路,不应直接复制到新项目。当前 webpack-dev-server 4+ 默认启用 HMR,严格 ESM 可使用 import.meta.webpackHot;生产环境不得携带 HMR runtime。以 webpack HMR 官方指南 和项目锁定版本为准。
# All in One 的弊端
通过 Webpack 实现前端项目整体模块化的优势固然明显,但是它也会存在一些弊端:它最终会将我们所有的代码打包到一起。试想一下,如果我们的应用非常复杂,模块非常多,那么这种 All in One 的方式就会导致打包的结果过大,甚至超过 4 ~ 5M。
在绝大多数的情况下,应用刚开始工作时,并不是所有的模块都是必需的。如果这些模块全部被打包到一起,即便应用只需要一两个模块工作,也必须先把 bundle.js 整体加载进来,而且前端应用一般都是运行在浏览器端,这也就意味着应用的响应速度会受到影响,也会浪费大量的流量和带宽。
所以这种 All in One 的方式并不合理,更为合理的方案是把打包的结果按照一定的规则分离到多个 bundle 中,然后根据应用的运行需要按需加载。这样就可以降低启动成本,提高响应速度。
其实这并不矛盾,只是物极必反罢了。Web 应用中的资源受环境所限,太大不行,太碎更不行。因为我们开发过程中划分模块的颗粒度一般都会非常的细,很多时候一个模块只是提供了一个小工具函数,并不能形成一个完整的功能单元。
如果我们不将这些资源模块打包,直接按照开发过程中划分的模块颗粒度进行加载,那么运行一个小小的功能,就需要加载非常多的资源模块。
再者,目前仍是主流(🐶)的 HTTP 1.1 本身就存在一些缺陷,例如:
- 同一个域名下的并行请求是有限制的;
- 每次请求本身都会有一定的延迟;
- 每次请求除了传输内容,还有额外的请求头,大量请求的情况下,这些请求头加在一起也会浪费流量和带宽。
综上所述,模块打包肯定是必要的,但当应用体积越来越大时,我们也要学会变通。
# Code Splitting
为了解决打包结果过大导致的问题,Webpack 设计了一种分包功能:Code Splitting(代码分割)。